package nautilus.lab.model;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import android.opengl.GLES20;
import android.util.Log;

public class Sphere{
	//Sphere position
	private float x = 0, y = 0, z = 0;
	private float R = 0;
	private static final int space = 10;
	private int verticeCount;
	private int programId;
	private int mPosHandler, mTextureHandler;
	private FloatBuffer vertexBuffer = null;
	private int stride = 5 * 4 /*Size of float in byte*/;
	
	private final String vertexShaderCode = "attribute vec4 aPosition;" +
											"void main(){" +
											"gl_Position = aPosition;}";
	private final String fragmentShaderCode = "precision mediump float;" +
											"uniform vec4 vColor;" +
											"void main(){" +
											"gl_FragColor = vColor;}";
	
	public Sphere(float r, float x, float y, float z) {
		this.R = r;
		/* Tinh cho goc 1/4 cua qua cau, sau do nhan 4 de duoc toan bo */
		verticeCount = (90/space + 1) * (180 / space+1) * 4;
		initVertices();
	}
	
	private void initVertices()	{
		/* Moi dinh bao gom mot bo: 3 thanh phan vi tri */
		ByteBuffer bvv = ByteBuffer.allocateDirect(verticeCount * 20); // verticeCount * dataElementCount * sizeofFloat = verticeCount * 5 * 4
		bvv.order(ByteOrder.nativeOrder());
		vertexBuffer = bvv.asFloatBuffer();
		
		float b, a;
		for(b=0; b<=90-space; b+=space)
			for(a=0; a<=180-space; a+=space){
				vertexBuffer.put((float)(R * Math.sin((a) / 180 * Math.PI) * Math.sin((b) / 180 * Math.PI) - this.x));
				vertexBuffer.put((float)(R * Math.cos((a) / 180 * Math.PI) * Math.sin((b) / 180 * Math.PI) + this.y));
				vertexBuffer.put((float)(R * Math.cos(b / 180 * Math.PI) - this.z));
				vertexBuffer.put((float) ((a) / 360));
				vertexBuffer.put((float) ((2 * b) / 360));
				
				vertexBuffer.put((float)(R * Math.sin((a) / 180 * Math.PI) * Math.sin((b + space) / 180 * Math.PI) - x));
				vertexBuffer.put((float)(R * Math.cos((a) / 180 * Math.PI) * Math.sin((b + space) / 180 * Math.PI ) + y));
				vertexBuffer.put((float)(R * Math.cos((b + space) / 180 * Math.PI) - z));
				vertexBuffer.put((float) ((a) / 360));
				vertexBuffer.put((float) ((2 * (b + space)) / 360));
				
				vertexBuffer.put((float)(R * Math.sin((a + space) / 180 * Math.PI) * Math.sin((b) / 180 * Math.PI) - x));
				vertexBuffer.put((float)(R * Math.cos((a + space) / 180 * Math.PI) * Math.sin((b) / 180 * Math.PI) + y));
				vertexBuffer.put((float)(R * Math.cos((b) / 180 * Math.PI) - z));
				vertexBuffer.put((float) ((a + space) / 360));
				vertexBuffer.put((float) ((2 * b) / 360));
				
				vertexBuffer.put((float)(R * Math.sin((a + space) / 180 * Math.PI) * Math.sin((b + space) / 180 * Math.PI) - x));
				vertexBuffer.put((float)(R * Math.cos((a + space) / 180 * Math.PI) * Math.sin((b + space) / 180 * Math.PI) + y));
				vertexBuffer.put((float)(R * Math.cos((b + space) / 180 * Math.PI) - z));
				vertexBuffer.put((float) ((a + space) / 360));
				vertexBuffer.put((float) ((2 * (b + space)) / 360));

			}
		vertexBuffer.position(0);
		
		/* Initialize shader */
		initShaders();
	}
	
	private void initShaders()	{
		
		Log.i("Sphere", "Reaches here 1 ");
		
		int vertexShaderId = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
		if(vertexShaderId == 0)
			throw new RuntimeException("Create vertex shader failed.");
		GLES20.glShaderSource(vertexShaderId, vertexShaderCode);
		GLES20.glCompileShader(vertexShaderId);
		
		int fragmentShaderId = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
		if(fragmentShaderId==0)
			throw new RuntimeException("Create fragment shader failed.");
		GLES20.glShaderSource(fragmentShaderId, fragmentShaderCode);
		GLES20.glCompileShader(fragmentShaderId);
		Log.i("Sphere", "Reaches here 2 ");
		programId = GLES20.glCreateProgram();
		GLES20.glAttachShader(programId, vertexShaderId);
		GLES20.glAttachShader(programId, fragmentShaderId);
		
		/* Bind attributes to shaders */
		GLES20.glBindAttribLocation(programId, 0, "aPosition");
		GLES20.glBindAttribLocation(programId, 1, "aColor");
		
		/* Link shaders into program */
		GLES20.glLinkProgram(programId);
		
		/* Set program handlers */
		mPosHandler = GLES20.glGetAttribLocation(programId, "aPosition");
		mTextureHandler = GLES20.glGetAttribLocation(programId, "vColor");
		
		GLES20.glUseProgram(programId);
	}
	
	public void draw() {
		/* vertex position offset */
		vertexBuffer.position(0);
		GLES20.glVertexAttribPointer(mPosHandler, 3, GLES20.GL_FLOAT, false, stride, vertexBuffer);
		GLES20.glEnableVertexAttribArray(mPosHandler);
		
		/* Texture information */
		vertexBuffer.position(3);
		GLES20.glVertexAttribPointer(mTextureHandler, 2/*texture data size*/,
				GLES20.GL_FLOAT, false, stride, vertexBuffer);
		GLES20.glEnableVertexAttribArray(mTextureHandler);
		
		//GLES20.glFrontFace(GLES20.GL_CW);
		
		GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, verticeCount);
		//
		//GLES20.glTe
	}
}